#include "field.hpp"
#include "meshTypeFunctions.hpp"
#include "bc_slip_velocity.hpp"
#include "util.hpp"

#include "testHelpers.hpp"

#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_approx.hpp>

using namespace hms;
using Type = hms::boundaryCondition::Type;
using Catch::Approx;

TEST_CASE( "Slip_velocity" ){

	auto test = []( auto&& dummyMesh ){
		using MeshType = remove_qualifiers<decltype(dummyMesh)>;
		auto mesh { uniMeshAs<MeshType>(3, 4, 1, 1, true) };
		using BC = Slip_velocity<MeshType>;

		const BoundaryPatch& left   { mesh.boundaryPatch("left") };
		const BoundaryPatch& right  { mesh.boundaryPatch("right") };
		const BoundaryPatch& bottom { mesh.boundaryPatch("bottom") };
		const BoundaryPatch& top    { mesh.boundaryPatch("top") };

		Field f { mesh, 2};

		auto setPatchesToBC = [&](){
			for ( const BoundaryPatch& p : mesh.boundaryPatches() )
				f.setBoundaryCondition( BC{f, p} ).update();
		};

		SECTION( "Flow from lower left to upper right corner"){
			f.values() = 1.0;
			setPatchesToBC();

			REQUIRE( (f.ghostValues(left).row(0)  == -1.0 ).all() );
			REQUIRE( (f.ghostValues(left).row(1)  ==  1.0 ).all() );
			REQUIRE( (f.ghostValues(right).row(0) == -1.0 ).all() );
			REQUIRE( (f.ghostValues(right).row(1) ==  1.0 ).all() );

			REQUIRE( (f.ghostValues(top).row(0)    ==  1.0 ).all() );
			REQUIRE( (f.ghostValues(top).row(1)    == -1.0 ).all() );
			REQUIRE( (f.ghostValues(bottom).row(0) ==  1.0 ).all() );
			REQUIRE( (f.ghostValues(bottom).row(1) == -1.0 ).all() );

			REQUIRE(f.boundaryCondition(left).type() == Type::slip_velocity);
		}
		SECTION( "Flow from upper right to lower left corner"){
			f.values() = -1.0;
			setPatchesToBC();

			REQUIRE( (f.ghostValues(left).row(0)  ==  1.0 ).all() );
			REQUIRE( (f.ghostValues(left).row(1)  == -1.0 ).all() );
			REQUIRE( (f.ghostValues(right).row(0) ==  1.0 ).all() );
			REQUIRE( (f.ghostValues(right).row(1) == -1.0 ).all() );

			REQUIRE( (f.ghostValues(top).row(0)    == -1.0 ).all() );
			REQUIRE( (f.ghostValues(top).row(1)    ==  1.0 ).all() );
			REQUIRE( (f.ghostValues(bottom).row(0) == -1.0 ).all() );
			REQUIRE( (f.ghostValues(bottom).row(1) ==  1.0 ).all() );
		}
	};
	TEST_ALL_MESHTYPES(test)
}